#include "sound.h"

// 程序中存储有一个周期的正弦波数据，为了产生正弦波音频输出，所以需要DMA
// 中断知道要发送多少个周期的正弦波，这个全局变量给DMA和主程序共用
uint32_t            remain_T;

// 程序中存储有其它音频数据，在使用DMA播放音频时，DMA一次只能传输65535个数据
// 这个全局变量会写入正在播放的音频数据的开始和结束地址，以便DMA判断有没有播放
// 完，是否需要再启动一个播放传输
uint32_t            startAddr, stopAddr;

// 播放音乐
uint8_t Play_Music(uint32_t start, uint32_t stop) {
    // 如果已启用DMA传输，则不做任何事情
    if(LL_DMA_IsEnabledChannel(DMA2, LL_DMA_CHANNEL_3)) {
        return ERROR;
    }

    // 设置参数
    LL_DMA_SetMemoryAddress(DMA2, LL_DMA_CHANNEL_3, start);

    if(stop - start > 0xFFFF) {
        LL_DMA_SetDataLength(DMA2, LL_DMA_CHANNEL_3, 0xFFFF);
        startAddr = start + 0xFFFF;
        stopAddr = stop;
    } else {
        LL_DMA_SetDataLength(DMA2, LL_DMA_CHANNEL_3, stop - start);
    }

    LL_DMA_SetMode(DMA2, LL_DMA_CHANNEL_3, LL_DMA_MODE_NORMAL);
    LL_TIM_SetAutoReload(TIM6, SystemCoreClock / 30000);
    // 开始通过DMA,通过DAC转换声音
    LL_DAC_EnableDMAReq(DAC1, LL_DAC_CHANNEL_1);
    LL_DMA_EnableChannel(DMA2, LL_DMA_CHANNEL_3);
    LL_DAC_Enable(DAC1, LL_DAC_CHANNEL_1);
    LL_TIM_EnableCounter(TIM6);
    return SUCCESS;
}

// 播放正弦波声音
void Play_Sin_Wave(uint32_t start, uint32_t stop, uint16_t frequency, uint16_t ms) {
    static uint16_t prev_frequent;

    if(LL_DMA_IsEnabledChannel(DMA2, LL_DMA_CHANNEL_3) && (prev_frequent == frequency)) {
        remain_T = ((double)ms * frequency / 1000);
        return;
    }

    prev_frequent = frequency;

    // 重新设置参数
    LL_DMA_SetMemoryAddress(DMA2, LL_DMA_CHANNEL_3, start);
    LL_DMA_SetDataLength(DMA2, LL_DMA_CHANNEL_3, stop - start);
    LL_DMA_SetMode(DMA2, LL_DMA_CHANNEL_3, LL_DMA_MODE_CIRCULAR);
    LL_TIM_SetAutoReload(TIM6, SystemCoreClock / (stop - start) / frequency);
    remain_T = ((double)ms * frequency / 1000);
    // 开始通过DMA,通过DAC转换声音
    LL_DAC_EnableDMAReq(DAC1, LL_DAC_CHANNEL_1);
    LL_DMA_EnableChannel(DMA2, LL_DMA_CHANNEL_3);
    LL_DAC_Enable(DAC1, LL_DAC_CHANNEL_1);
    LL_TIM_EnableCounter(TIM6);
}

// beep
void beep()
{
    Play_Sin_Wave((uint32_t)&WAVE01, (uint32_t)&WAVE01_END, 523, 100);
}

void error_beep()
{
    Play_Sin_Wave((uint32_t)&WAVE01, (uint32_t)&WAVE01_END, 880, 100);
    LL_mDelay(10000);
}